import accounting from 'accounting';
import { DownOutlined } from '@ant-design/icons';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Menu, Dropdown, Button, message, Spin } from 'antd';
import { connect } from 'dva';
import _ from 'lodash';
import debounce from 'lodash/debounce';
import moment from 'moment';
import React, { PureComponent } from 'react';
import { times } from 'number-precision';
import myStyle from './index.less';
import PoolExport from './poolExport';
import SelectColumns from './selectColumns';

import { SingleDateC, PrimaryC, PrimaryGhostC, TableC, SecuritiesCodeC, InputNumberC, UploadC } from '../../../../comps';
import { exportFile } from '../../../../utils/commonFunc';

const { SubMenu } = Menu;
@Form.create()
@connect(({ loading, workStationM }) => ({ loading, workStationM }))
export default class HoldManage extends PureComponent {
  // eslint-disable-next-line react/static-property-placement
  static defaultProps = {
    onRef: () => {}, // 本组件的引用
  };

  constructor(props) {
    super(props);

    this.state = {
      totalDataSource: [], // 统计信息
      totalDataSourceForAdjust: [],
      dataSource: [], // 表格数据
      historyData: [], // 历史数据
      historyTotalDataSource: [],
      visible: false, // 更多操作下拉菜单是否显示
      productCode: '', // 组合code
      query: {
        // 查询条件
        date: moment().format('YYYY-MM-DD'),
      },
      checkedKeysInfo: [], // 列选择key
      columns: [], // 表头
      isEdit: false, // 是否手动调仓
      securityCode: undefined, // 证券代码信息
      poolShow: false, // 券池导入模态框
      currentPage: 1, // 页码
      pageSize: 10, // 每页数量
    };

    // 绑定lodash的防抖函数
    this.positiomChange = debounce(this.positiomChange, 500);
    this.weightChange = debounce(this.weightChange, 500);
  }

  componentDidMount() {
    this.dateChange(undefined, true);
    this.props.OnRef(this);
    // componentDidMount取消请求会导致真实组合切换至模拟组合传的产品id还是之前真实的 放到props改变时在请求
    // const { portfolioList } = this.props.workStationM;
    // const { productCode } = this.props;
    // const res = portfolioList.find((v) => v.portfolioCode == productCode);
    //
    // if (this.props.productCode) {
    //   this.setState(
    //     {
    //       query: {
    //         portfolioId: this.props.productCode,
    //         date: this.state.query.date ? this.state.query.date : moment().format('YYYY-MM-DD'),
    //       },
    //       productCode: this.props.productCode,
    //     },
    //     () => {
    //       if (res && res.portfolioType != 1) {
    //         this.getData();
    //       }
    //     },
    //   );
    // }
  }

  // eslint-disable-next-line react/no-deprecated
  UNSAFE_componentWillReceiveProps(nextProps) {
    const nextDate = !nextProps.date ? '' : JSON.stringify(nextProps.date); // 一键调仓的产品时间参数
    const preDate = !this.props.date ? '' : JSON.stringify(this.props.date); // 一键调仓的产品时间参数

    const init = !this.props.productCode ? '' : JSON.stringify(this.props.productCode);
    const initN = !nextProps.productCode ? '' : JSON.stringify(nextProps.productCode);
    const {
      form: { setFieldsValue },
    } = this.props;
    if (init != initN || nextDate !== preDate) {
      nextDate !== preDate ? this.onCancel() : null; // 一键调仓时候  手动调仓取消响应
      const { portfolioList } = nextProps.workStationM;
      const { productCode } = nextProps;
      const res = portfolioList.find((v) => v.portfolioCode == productCode);
      setFieldsValue({ date: nextDate !== '' ? moment(nextProps.date) : moment() }); // 一键调仓的产品时间参数存在则使用
      this.setState(
        {
          query: {
            portfolioId: nextProps.productCode,
            date: nextDate !== '' ? nextProps.date : moment().format('YYYY-MM-DD'), // 一键调仓的产品时间参数存在则使用
          },
          productCode: nextProps.productCode,
        },
        () => {
          if (res && res.portfolioType != 1) {
            // 响应一键调节仓乘 amount * 当前的权重 作为新的权重
            const callback = () => {
              if (this.props.holdingInfos.length > 0) {
                const { weight } = this.state.totalDataSourceForAdjust[2]; // 股票的amount
                const data = _.cloneDeep(this.state.dataSource);
                data.map((item, index) => {
                  const everyitem = this.props.holdingInfos[index];
                  if (item.securitiesCode === everyitem.tradingCode) {
                    const res = times(weight ? weight : 1, everyitem.amount);
                    item.holdingNum = res; // 调仓接口取得holdingNum作为amount ，
                    item.type = everyitem.type; // type是1传的代表权重， 0代表数量
                  }
                });
                this.setState(
                  {
                    dataSource: data,
                  },
                  () => {
                    // 设置成功后手动调用 手动调仓按钮
                    this.onOk();
                  },
                );
              }
            };
            this.getData(callback);
          }
        },
      );
    }
    if (this.props.updateState != nextProps.updateState) {
      if (this.state.query.portfolioId) {
        this.getData();
      }
    }
  }

  // 获取持仓列表
  getData = (callback) => {
    this.changeColumns();
    this.props.dispatch({
      type: 'workStationM/queryHoldData',
      payload: this.state.query,
      callback: (res, totalDataSourceForAdjust) => {
        if (res) {
          this.setState(
            {
              totalDataSource: res.totalDataSource,
              dataSource: res.dataSource,
              totalDataSourceForAdjust,
            },
            () => {
              callback && callback();
            },
          );
        } else if ([null, undefined].includes(res)) {
          this.setState({
            totalDataSource: [],
            totalDataSourceForAdjust: [],
            dataSource: [],
          });
        }
      },
    });
  };

  // 改变持仓列头
  changeColumns = () => {
    const { isEdit } = this.state;
    const {
      workStationM: { columns },
    } = this.props;
    const newColumns = _.cloneDeep(columns).filter((i) => i.display == true);
    newColumns.map((item) => {
      if (item.key == 'holdingNum') {
        item.render = (val, record) => {
          if (isEdit) {
            return (
              <div style={{ minWidth: '90px' }}>
                <InputNumberC
                  form={this.props.form}
                  dataIndex={`holdingNum${record.securitiesCode}`}
                  initialValue={val || ''}
                  precision={0}
                  min={0}
                  splitStyle={true}
                  onChange={(e) => this.positiomChange(e, record.securitiesCode)}
                  rules={[{ required: true, message: ' ' }]}
                />
              </div>
            );
          }
          if (val == null || val === undefined || val === '') {
            return '--';
          }
          // NaN: Not a Number
          // isNaN()的缺点就在于 null、空格以及空串会被按照0来处理
          // eslint-disable-next-line no-restricted-globals
          if (isNaN(val)) {
            return val;
          }
          return accounting.formatNumber(Number(val), 0);
        };
      }
      if (item.key == 'holdingWeight') {
        item.render = (val, record) => {
          if (isEdit) {
            return (
              <div style={{ minWidth: '90px' }}>
                <InputNumberC
                  form={this.props.form}
                  dataIndex={`holdingWeight${record.securitiesCode}`}
                  initialValue={val ? times(Number(val), 100) : ''}
                  precision={2}
                  min={0}
                  rules={[{ required: true, message: ' ' }]}
                  onChange={(e) => this.weightChange(e, record.securitiesCode)}
                />
              </div>
            );
          }
          if (val == null || val === undefined || val === '') {
            return '--';
          }
          // NaN: Not a Number
          // isNaN()的缺点就在于 null、空格以及空串会被按照0来处理
          // eslint-disable-next-line no-restricted-globals
          if (isNaN(val)) {
            return val;
          }
          // 乘除
          const multiplyValue = times(Number(val), 100);
          return multiplyValue?.toFixed(2);
        };
      }
    });
    // return newColumns
    this.setState({ columns: newColumns });
  };

  // 持仓数量变更响应
  positiomChange = (e, securitiesCode) => {
    const {
      form: { setFieldsValue },
    } = this.props;
    const { dataSource, totalDataSource } = this.state;
    // eslint-disable-next-line no-restricted-globals
    if (isNaN(Number(e)) || e < 0) return;
    if (e == null || e == '') {
      message.error('请输入持仓数量');
      return;
    }
    dataSource.map((i) => {
      if (i.securitiesCode == securitiesCode) {
        i.holdingNum = e; // 个股持仓数量
        if (!i.closingPrice) {
          message.error('未获取最新收盘价');
          return;
        }
        i.marketvalue = e * i.closingPrice; // 个股持仓市值 公式：个股持仓市值=个股持仓数量*最新收盘价
        if (totalDataSource[2].value0 <= 0) {
          message.error('总计持仓市值不得小于0');
          return;
        }
        setFieldsValue({ [`holdingWeight${securitiesCode}`]: ((e * i.closingPrice) / totalDataSource[2].value0) * 100 }); // 个股权重  公式个股调整后权重=个股调整后持仓数量*最新收盘价/总计持仓市值
        i.holdingWeight = ((e * i.closingPrice) / totalDataSource[2].value0) * 100; // 个股权重
        totalDataSource[1].value2 = dataSource.reduce((p, v) => p + v.holdingWeight, 0); // 股票权重 ,个股权重和
        totalDataSource[2].value2 = dataSource.reduce((p, v) => p + v.marketvalue, 0); // 股票持仓市值，个股持仓市值和
        totalDataSource[2].value1 = totalDataSource[2].value0 - totalDataSource[2].value2; // 现金持仓市值，公式：调整后现金持仓市值=总计持仓市值-股票持仓市值；
        totalDataSource[1].value1 = totalDataSource[1].value0 - totalDataSource[1].value2; // 现金权重，公式：调整后现金权重=总计权重-股票权重
        this.changeColumns();
      }
    });
  };

  // 权重变更响应
  weightChange = (e, securitiesCode) => {
    const {
      form: { setFieldsValue },
    } = this.props;
    const { dataSource, totalDataSource } = this.state;
    // eslint-disable-next-line no-restricted-globals
    if (isNaN(Number(e)) || e < 0) return;
    if (e == null || e == '') {
      message.error('请输入权重');
      return;
    }
    dataSource.map((i) => {
      if (i.securitiesCode == securitiesCode) {
        i.holdingWeight = e / 100; // 个股权重
        if (!i.closingPrice) {
          message.error('未获取最新收盘价');
          return;
        }
        if (totalDataSource[2].value0 <= 0) {
          message.error('总计持仓市值不得小于0');
          return;
        }
        setFieldsValue({ [`holdingNum${securitiesCode}`]: (e * totalDataSource[2].value0) / i.closingPrice / 100 }); // 个股持仓数量,个股调整后持仓数量=个股调整后权重*总计持仓市值/最新收盘价

        i.holdingNum = (e * totalDataSource[2].value0) / i.closingPrice / 100; // 个股持仓数量
        i.marketvalue = (e * totalDataSource[2].value0) / 100; // 个股持仓市值，个股调整后持仓市值=个股调整后权重*总计持仓市值
        totalDataSource[1].value2 = dataSource.reduce((p, v) => p + v.holdingWeight, 0); // 调整后股票权重,个股权重和
        totalDataSource[2].value2 = dataSource.reduce((p, v) => p + v.marketvalue, 0); // 股票持仓市值，个股持仓市值和
        totalDataSource[2].value1 = totalDataSource[2].value0 - totalDataSource[2].value2; // 现金持仓市值，调整后现金持仓市值=总计持仓市值-股票持仓市值；
        totalDataSource[1].value1 = totalDataSource[1].value0 - totalDataSource[1].value2; // 现金权重，调整后现金权重=总计权重-股票权重
        this.changeColumns();
      }
    });
  };

  // 更多操作下拉点击
  handleMenuClick = (e) => {
    // eslint-disable-next-line default-case
    switch (e.key) {
      case 'export':
        this.export();
        break;
      case 'poolImport':
        this.poolImport();
        break;
      case 'download1':
        this.download(1);
        break;
      case 'download2':
        this.download(2);
        break;
    }
    if (e.key !== 'column') {
      this.setState({ visible: false });
    }
  };

  // 更多操作下拉
  menu = () => (
    <Menu onClick={this.handleMenuClick}>
      <Menu.Item key='realPortfolio'>转真实组合</Menu.Item>
      <Menu.Item key='export'>导出</Menu.Item>
      <Menu.Item key='column'>
        <SelectColumns changeColumns={this.changeColumns} />
      </Menu.Item>
    </Menu>
  );

  // 数据导入下拉
  dataExportMenu = () => (
    <Menu onClick={this.handleMenuClick}>
      <Menu.Item key='poolImport'>券池导入</Menu.Item>
      <SubMenu key='mouldImport' title='模板导入'>
        <Menu.Item key='mouldImport1'>
          <UploadC
            title='持仓数量导入'
            accept='.xlsx,.xls'
            showUploadList={false}
            type={2}
            isButton={false}
            onUpload={(e) => {
              this.mouldImport(e, 0);
            }}
          />
        </Menu.Item>
        <Menu.Item key='mouldImport2'>
          <UploadC
            title='持仓权重导入'
            accept='.xlsx,.xls'
            showUploadList={false}
            type={2}
            isButton={false}
            onUpload={(e) => {
              this.mouldImport(e, 1);
            }}
          />
        </Menu.Item>
      </SubMenu>
      <SubMenu key='download' title='模板下载'>
        <Menu.Item key='download1'>持仓数量模板</Menu.Item>
        <Menu.Item key='download2'>持仓权重模板</Menu.Item>
      </SubMenu>
    </Menu>
  );

  // 手动调仓点击
  onClick = () => {
    const historyData = _.cloneDeep(this.state.dataSource);
    const historyTotalDataSource = _.cloneDeep(this.state.totalDataSource);
    this.setState({ isEdit: true, historyData, historyTotalDataSource }, () => this.changeColumns());
    this.props.changeportfilio(true);
  };

  // 导出
  export = () => {
    exportFile('gateway/file/maat-workstation/barraPosition/export', this.state.query);
  };

  // 券池导入
  poolImport = () => {
    this.setState({ poolShow: true });
  };

  // 模板导入
  mouldImport = (file, type) => {
    const formData = new FormData();
    formData.append('file', file);
    this.props.dispatch({
      type: 'workStationM/mouldImport',
      payload: { formData, type, portfolioId: this.state.productCode },
      callback: (data) => {
        if (data) {
          this.props.changeUpdataState();
          this.getData();
        }
      },
    });
  };

  // 模板下载
  download = (flag) => {
    exportFile('gateway/maat-workstation/barraPosition/download', { flag });
  };

  // 更多操作
  handleVisibleChange = (flag) => {
    this.setState({ visible: flag });
  };

  // 日期变化响应
  dateChange = (e, isFirst = false) => {
    // 判断是否为节假日 当选择节假日后，【添加交易】按钮置灰，用户不能进行交易；其他保持不变
    const startDate = isFirst ? moment().startOf('month').format('YYYY-MM-DD') : moment(e).startOf('month').format('YYYY-MM-DD');
    const endDate = isFirst ? moment().endOf('month').format('YYYY-MM-DD') : moment(e).endOf('month').format('YYYY-MM-DD');
    // eslint-disable-next-line radix
    const day = isFirst ? parseInt(moment().format('DD')) - 1 : parseInt(moment(e).format('DD')) - 1;
    this.props.dispatch({
      type: 'globalM/queryHoliday',
      payload: {
        startDate,
        endDate,
        calendarType: 1,
      },
      callback: (type, data) => {
        if (type == 'success') {
          this.setState({
            isHoliday: data[day].isHoliday,
          });
        }
      },
    });
    this.setState(
      {
        query: {
          ...this.state.query,
          date: moment(e).format('YYYY-MM-DD'),
        },
      },
      () => {
        if (this.state.query.portfolioId) {
          this.getData();
        }
      },
    );
  };

  // 证券代码改变响应
  handleChange = (e) => {
    this.setState({ securityCode: e });
  };

  // 调仓确定响应
  onOk = () => {
    const {
      form: { validateFields, setFieldsValue },
    } = this.props;
    validateFields((err) => {
      if (!err) {
        if (this.state.totalDataSource[2].value1 < 0) {
          message.error('现金不足');
          return;
        }
        const holdingInfos = [];
        this.state.dataSource.map((i) => {
          holdingInfos.push({
            tradingCode: i.securitiesCode,
            exchangeCode: i.exchangeCode,
            amount: i.holdingNum,
            type: i.type,
            holdingDate: this.state.query.date,
          });
        });
        if (holdingInfos.length == 0) {
          message.error('无持仓数据');
          return;
        }
        this.props.dispatch({
          type: 'workStationM/changePosition',
          payload: {
            portfolioId: this.state.productCode,
            holdingInfos,
          },
          callback: (res) => {
            if (res) {
              this.setState({ isEdit: false });
              this.props.changeUpdataState();
              setFieldsValue({ date: moment(this.state.query.date) });
              this.props.changeportfilio(false);
              // 调仓成功需要设置调仓参数恢复
              this.props.dispatch({
                type: 'workStationM/setState',
                payload: {
                  adjustArgs: {
                    productCode: undefined,
                    date: moment().format('YYYY-MM-DD'),
                    holdingInfos: [],
                  },
                },
              });
            }
          },
        });
      }
    });
  };

  // 调仓取消响应
  onCancel = () => {
    this.props.changeportfilio(false);
    this.setState({ isEdit: false, dataSource: this.state.historyData, totalDataSource: this.state.historyTotalDataSource }, () => this.changeColumns());
  };

  // 添加证券代码
  add = () => {
    const { securityCode, dataSource } = this.state;
    if (!securityCode) {
      message.info('请先选择证券代码！');
      return;
    }
    if (dataSource.some((i) => i.securitiesCode.split('.')[0] == securityCode.tradingCode)) {
      message.error('您选择的股票已在持仓中。');
      return;
    }
    this.props.dispatch({
      type: 'workStationM/getLatestPrice',
      payload: [
        {
          exchangeCode: securityCode.exchangeCode,
          tradingCode: securityCode.tradingCode,
          date: this.state.query.date,
        },
      ],
      callback: (res) => {
        let newData = {};
        if (res) {
          newData = {
            securitiesName: securityCode.secuabbr,
            securitiesCode: securityCode.tradingCode,
            closingPrice: res.preClosePx,
            exchangeCode: securityCode.exchangeCode,
          };
        } else {
          newData = {
            securitiesName: securityCode.secuabbr,
            exchangeCode: securityCode.exchangeCode,
            securitiesCode: securityCode.secucode,
          };
        }
        this.setState(
          {
            dataSource: [newData, ...dataSource],
          },
          () => this.changeColumns(),
        );
      },
    });
  };

  // 券池导入取消
  changeVisible = () => {
    this.setState({ poolShow: false });
  };

  // 券池导入确认
  poolOk = () => {
    this.setState({ poolShow: false });
    this.props.changeUpdataState();
  };

  // 表格页码响应
  handleTableChange = (pagination) => {
    const { current, pageSize } = pagination;
    this.setState({
      currentPage: current,
      pageSize,
    });
  };

  render() {
    const { totalDataSource, dataSource, visible, columns, isEdit, poolShow, currentPage, pageSize } = this.state;
    const { loading, minDate, maxDate } = this.props;
    const formItemLayout = {
      labelCol: {
        span: 4,
      },
      wrapperCol: {
        span: 18,
      },
    };
    if (columns && columns.length > 8) {
      const a = columns.length;
      this.scrollx = a * 100;
    } else {
      this.scrollx = 0;
    }
    return (
      <div>
        <div className={myStyle.holdSearch} style={{ display: 'flex' }}>
          <div style={{ flex: isEdit ? '0' : '1' }}>
            <div style={{ width: '226px' }}>
              <SingleDateC
                form={this.props.form}
                dataIndex='date'
                title='日期'
                initialValue={moment(this.state.query.date)}
                formItemLayout={formItemLayout}
                onChange={(e) => this.dateChange(e, false)}
                disableBegin={moment(minDate).subtract(1, 'day')}
                disableEnd={moment(maxDate).add(1, 'day')}
                disabled={isEdit}
              />
            </div>
          </div>
          {isEdit && (
            <div className={myStyle.holdSearch} style={{ display: 'flex', flex: '1' }}>
              <div style={{ flex: '1' }}>
                <div style={{ display: 'flex', width: '293px' }}>
                  <SecuritiesCodeC
                    form={this.props.form}
                    dataIndex='securityCode'
                    titleDisplay={false}
                    codeType='stock'
                    positionBody={true}
                    placeholder='请输入证券代码'
                    onChange={this.handleChange}
                  />
                  <PrimaryGhostC title='添加' onClick={this.add} style={{ marginLeft: '15px', paddingTop: '5px' }} />
                </div>
              </div>
              <div style={{ paddingTop: '5px' }}>
                <PrimaryC title='确定' onClick={this.onOk} />
              </div>
              <div style={{ marginLeft: '15px', paddingTop: '5px' }}>
                <PrimaryGhostC title='取消' onClick={this.onCancel} />
              </div>
            </div>
          )}
          {!isEdit && (
            <div style={{ paddingTop: '5px' }}>
              <PrimaryC disabled={this.state.isHoliday == 0} title='手动调仓' onClick={this.onClick} />
            </div>
          )}
          {!isEdit && (
            <div className={myStyle.dataExport}>
              <Dropdown overlay={this.dataExportMenu} trigger={['click']}>
                <Button>
                  数据导入 <DownOutlined />
                </Button>
              </Dropdown>
            </div>
          )}
          {!isEdit && (
            <div className={myStyle.moreOperation}>
              <Dropdown overlay={this.menu} onVisibleChange={this.handleVisibleChange} visible={visible} trigger={['click']}>
                <Button>
                  更多操作 <DownOutlined />
                </Button>
              </Dropdown>
            </div>
          )}
        </div>

        <div>
          <Spin spinning={loading.effects['workStationM/queryHoldData'] == true}>
            <div className={myStyle.wrap}>
              {totalDataSource && totalDataSource.length ? (
                <>
                  {totalDataSource.map((item, key) => (
                    // eslint-disable-next-line react/no-array-index-key
                    <div key={key} style={{ width: `${100 / totalDataSource.length}%` }}>
                      <div>{item.name}</div>
                      {/* eslint-disable-next-line max-len */}
                      <div>
                        {item.value0 != undefined && item.value0 != null
                          ? item.value0 == '总计'
                            ? '总计'
                            : accounting.formatNumber(Number(item.value0), item.toFixed || 2)
                          : '--'}
                      </div>
                      {/* eslint-disable-next-line max-len */}
                      <div>
                        {item.value1 != undefined && item.value1 != null
                          ? item.value1 == '现金'
                            ? '现金'
                            : accounting.formatNumber(Number(item.value1), item.toFixed || 2)
                          : '--'}
                      </div>
                      {/* eslint-disable-next-line max-len */}
                      <div>
                        {item.value2 != undefined && item.value2 != null
                          ? item.value2 == '股票'
                            ? '股票'
                            : accounting.formatNumber(Number(item.value2), item.toFixed || 2)
                          : '--'}
                      </div>
                    </div>
                  ))}
                </>
              ) : null}
            </div>
          </Spin>
          <div className={myStyle.table}>
            <TableC
              columns={columns || []}
              dataSource={dataSource || []}
              onChange={this.handleTableChange}
              scroll={{ x: this.scrollx, y: 160 }}
              loading={loading.effects['workStationM/queryHoldData']}
              rowKey='key'
              current={currentPage}
              pageSize={pageSize}
              size='small'
            />
          </div>
        </div>
        {poolShow && (
          <PoolExport
            visible={poolShow}
            changeVisible={this.changeVisible}
            productCode={this.props.productCode}
            poolOk={this.poolOk}
            tableData={_.cloneDeep(dataSource) || []}
            date={this.state.query.date}
          />
        )}
      </div>
    );
  }
}
